using System;
using System.Collections.Generic;
using System.Reflection;

namespace SiliverlightJavascriptIntelli
{
    public class SilverlightMethod : IJavascriptConvertable
    {
        private string name;
        private string returnValueType;
        private SilverlightParameterCollection parameters = new SilverlightParameterCollection();
        private bool isReturnValueTypeInteger;
        private SilverlightType belongTo;
        private string description;

        public SilverlightMethod(SilverlightType belongTo, string Name, string Description, string ReturnValueType, string ReturnDescription, params SilverlightParameter[] parameters)
        {
            this.belongTo = belongTo;
            this.Name = Name;
            this.Description = Description + ReturnDescription;
            this.ReturnValueType = ReturnValueType;
            this.IsReturnValueTypeInteger = TypeHelper.IsTypeInteger(ReturnValueType);

            foreach (SilverlightParameter parameter in parameters)
            {
                this.Parameters.Add(parameter);
                parameter.BelongsTo = this;
            }
        }


        public static SilverlightMethod ConvertMethodInfoToSilverlightMethod(MethodInfo curMethodInfoToConvert, SilverlightType typeToAddTo)
        {
            SilverlightMethod newMethod = new SilverlightMethod(typeToAddTo);

            newMethod.Name = curMethodInfoToConvert.Name;
            newMethod.ReturnValueType = TypeHelper.ConvertTypeToString(curMethodInfoToConvert.ReturnType);
            newMethod.IsReturnValueTypeInteger = TypeHelper.IsTypeInteger(curMethodInfoToConvert.ReturnType);
            newMethod.Description = ReferenceAnalyzer.GetDescrptionForMethod(newMethod.Name);

            foreach (ParameterInfo curParameterInfoToConvertToSilverlightParam in curMethodInfoToConvert.GetParameters())
            {
                newMethod.Parameters.Add(
                    SilverlightParameter.ConvertParameterInfoToSilverlightParameter(curParameterInfoToConvertToSilverlightParam, newMethod));
            }

            return newMethod;
        }

        public string Name
        {
            get
            {
                return StringHelper.FirstLetterToLower(name);
            }
            set
            {
                name = value;
            }
        }

        public string ReturnValueType
        {
            get
            {
                return returnValueType;
            }
            set
            {
                returnValueType = value;
            }
        }

        public SilverlightParameterCollection Parameters
        {
            get
            {
                return parameters;
            }
        }

        public bool IsReturnValueTypeInteger
        {
            get
            {
                return isReturnValueTypeInteger;
            }
            set
            {
                isReturnValueTypeInteger = value;
            }
        }

        public SilverlightType BelongTo
        {
            get
            {
                return belongTo;
            }
            set
            {
                belongTo = value;
            }
        }

        private string Description
        {
            get
            {
                return description;
            }
            set
            {
                description = value;
            }
        }

        public SilverlightMethod(SilverlightType belongTo)
        {
            this.belongTo = belongTo;
        }



        public string ToJavascript()
        {

            string ReturnValue = string.Empty;

            ReturnValue += StringHelper.Format(JavascriptFormats.FunctionHeader, this.BelongTo.Name, this.Name,
                GetAllParametersByNameForSignature(), this.Description);

            ReturnValue += GetAllParametersComments();

            if (this.ReturnValueType != null)
                ReturnValue += GetJavascriptReturnsCommentForType(this.ReturnValueType,
                                                                  this.IsReturnValueTypeInteger.ToString());

            ReturnValue += StringHelper.Format(JavascriptFormats.JavacriptFunctionInvocationFormat,
                                               this.Name,
                                               GetAllParametersByNameForSignature(),
                                                TypeHelper.GetConvertToPrefixForType(this.ReturnValueType),
                                                 GetAllParametersByNameForInvocation(),
                                                GetAllParametersWithNameAndTypeForTypeSafety())
                                                + JavascriptFormats.OneBreakLine;


            ReturnValue += JavascriptFormats.FunctionEnd;

            return ReturnValue;
        }

        private string GetAllParametersWithNameAndTypeForTypeSafety()
        {
            List<string> paramNames =
                 this.Parameters.ConvertAll<string>(
                     delegate(SilverlightParameter param)
                     {
                         return "\"" + param.Type + "\":" + param.Name;
                     });

            return "{" + String.Join(", ", paramNames.ToArray()) + "}";
        }

        private string GetAllParametersByNameForInvocation()
        {
            List<string> paramNames =
                 this.Parameters.ConvertAll<string>(
                     delegate(SilverlightParameter param)
                     {
                         return param.Name + TypeHelper.GetExtractFromPrefixFor(param.Type);
                     });

            return String.Join(", ", paramNames.ToArray());
        }


        public static string GetJavascriptReturnsCommentForType(string type, string IsInteger)
        {
            return StringHelper.Format(JavascriptFormats.JavascriptReturnsCommentFormat, type, IsInteger);
        }

        public string GetAllParametersComments()
        {
            string ReturnValue = string.Empty;

            foreach (SilverlightParameter parameterToAddToJavascriptComments in this.Parameters)
            {
                ReturnValue += parameterToAddToJavascriptComments.ToJavascript();
            }

            return ReturnValue;
        }

        public string GetAllParametersByNameForSignature()
        {
            List<string> paramNames =
                this.Parameters.ConvertAll<string>(
                    delegate(SilverlightParameter param)
                    {
                        return param.Name;
                    });

            return String.Join(", ", paramNames.ToArray());
        }

        public override bool Equals(object obj)
        {
            SilverlightMethod otherMethod = obj as SilverlightMethod;
            if (otherMethod != null)
            {
                return ((this.Name == otherMethod.Name)
                        && (this.Parameters == otherMethod.Parameters));
            }
            else
                return base.Equals(obj);
        }

        public static bool operator ==(SilverlightMethod x, SilverlightMethod y)
        {
            bool isEqual;
            if (object.ReferenceEquals(x, null))
            {
                if (object.ReferenceEquals(y, null))
                {
                    isEqual = true;
                }
                else
                {
                    isEqual = false;
                }
            }
            else
            {
                isEqual = x.Equals(y);
            }
            return isEqual;
        }


        public static bool operator !=(SilverlightMethod x, SilverlightMethod y)
        {
            return !(x == y);
        }
    }
}